/*Copyright ©2015 TommyLemon(https://github.com/TommyLemon)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
limitations under the License.*/

package zuo.biao.library.base;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.fraction.FractionAbility;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.KeyEvent;
import zuo.biao.library.interfaces.AbilityPresenter;
import zuo.biao.library.interfaces.OnBottomDragListener;
import zuo.biao.library.manager.ThreadManager;
import zuo.biao.library.ui.LoadingDialog;
import zuo.biao.library.util.CommonUtil;
import zuo.biao.library.util.Log;
import zuo.biao.library.util.ResTUtil;
import zuo.biao.library.util.StringUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 通过继承可获取或使用 里面创建的 组件 和 方法
 * *onFling内控制左右滑动手势操作范围，可自定义
 *
 * @author Lemon
 * @use extends BaseAbility
 * @see #context
 * @see #view
 * @see #setContentView
 * @see #runUiThread
 * @see #runThread
 */
public abstract class BaseAbility extends FractionAbility implements AbilityPresenter {
    private static final String TAG = "BaseActivity";

    @Override
    public BaseAbility getAbility() {
        return this; // 必须return this;
    }

    /**
     * 该Activity实例，命名为context是因为大部分方法都只需要context，写成context使用更方便
     *
     * @warn 不能在子类中创建
     */
    protected BaseAbility context = null;
    /**
     * 该Activity的界面，即contentView
     *
     * @warn 不能在子类中创建
     */
    protected Component view = null;

    private boolean isAlive = false;
    private boolean isRunning = false;

    @Override
    protected void onStart(Intent intent) {
        super.onStart(intent);
        context = (BaseAbility) getAbility();
        isAlive = true;
        threadNameList = new ArrayList<String>();
    }

    /**
     * 默认标题TextView，layout.xml中用@id/tvBaseTitle绑定。子Activity内调用autoSetTitle方法 会优先使用INTENT_TITLE
     *
     * @warn 如果子Activity的layout中没有android:id="@id/tvBaseTitle"的TextView，使用前必须在子Activity中赋值
     * @see #autoSetTitle
     */
    protected Text tvBaseTitle;

    /**
     * 设置root id
     * @param layoutResID id
     */
    public void setContentView(int layoutResID) {
        setUIContent(layoutResID);
    }

    // 底部滑动实现同点击标题栏左右按钮效果<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    private OnBottomDragListener onBottomDragListener;
//    private GestureDetector gestureDetector;
    /**
     * 设置该Activity界面布局，并设置底部左右滑动手势监听
     *
     * @param layoutResID layoutResID
     * @param listener listener
     * @use 在子类中
     * *1.onCreate中super.onCreate后setContentView(layoutResID, this);
     * *2.重写onDragBottom方法并实现滑动事件处理
     * *3.在导航栏左右按钮的onClick事件中调用onDragBottom方法
     */
    public void setContentView(int layoutResID, OnBottomDragListener listener) {
        setContentView(layoutResID);

        onBottomDragListener = listener;
    }

    // 底部滑动实现同点击标题栏左右按钮效果>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    /**
     * 用于 打开activity以及activity之间的通讯（传值）等；一些通讯相关基本操作（打电话、发短信等）
     */
    protected Intent intent = null;

    /**
     * 退出时之前的界面进入动画,可在finish();前通过改变它的值来改变动画效果
     */
    protected int enterAnim = 0;
    /**
     * 退出时该界面动画,可在finish();前通过改变它的值来改变动画效果
     */
    protected int exitAnim = 0;

    /**
     * 通过id查找并获取控件，使用时不需要强转
     *
     * @param id id
     * @return findView
     */
    public <V extends Component> V findView(int id) {
        return (V) findView(id);
    }

    /**
     * 通过id查找并获取控件，并setOnClickListener
     *
     * @param id id
     * @param l l
     * @return findView
     */
    public <V extends Component> V findView(int id, Component.ClickedListener l) {
        V v = findView(id);
        v.setClickedListener(l);
        return v;
    }

    /**
     * 通过id查找并获取控件，并setOnClickListener
     *
     * @param id id
     * @param l l
     * @return findViewById
     */
    public <V extends Component> V findViewById(int id, Component.ClickedListener l) {
        return findView(id, l);
    }

    // 自动设置标题方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**
     * 自动把标题设置为上个Activity传入的INTENT_TITLE，建议在子类initView中使用
     * *这个方法没有return，tvTitle = tvBaseTitle，直接用tvBaseTitle
     *
     * @must 在UI线程中调用
     */
    protected void autoSetTitle() {
        tvBaseTitle = autoSetTitle(tvBaseTitle);
    }

    /**
     * 自动把标题设置为上个Activity传入的INTENT_TITLE，建议在子类initView中使用
     *
     * @param tvTitle tvTitle
     * @return tvTitle 返回tvTitle是为了可以写成一行，如 tvTitle = autoSetTitle((TextView) findViewById(titleResId));
     * @must 在UI线程中调用
     */
    protected Text autoSetTitle(Text tvTitle) {
        if (tvTitle != null && StringUtil.isNotEmpty(getIntent().getStringParam(INTENT_TITLE), false)) {
            tvTitle.setText(StringUtil.getCurrentString());
        }
        return tvTitle;
    }

    // 自动设置标题方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    // 显示与关闭进度弹窗方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**
     * 进度弹窗
     */
    LoadingDialog progressDialog;

    /**
     * 展示加载进度条,无标题
     *
     * @param stringResId stringResId
     */
    public void showProgressDialog(int stringResId) {
        try {
            showProgressDialog(ResTUtil.getString(context, stringResId));
        } catch (Exception e) {
            Log.error(
                    TAG,
                    "showProgressDialog  showProgressDialog(null, context.getResources().getString(stringResId));");
        }
    }

    /**
     * 展示加载进度条,无标题
     */
    public void showProgressDialog() {
        showProgressDialog("加载中…");
    }

    /**
     * 展示加载进度条
     *
     * @param message 信息
     */
    public void showProgressDialog(final String message) {
        runUiThread(
                new Runnable() {
                    @Override
                    public void run() {
                        if (progressDialog == null) {
                            progressDialog = new LoadingDialog(getAbility());
                        }
                        progressDialog.setLoadText(message);
                        progressDialog.setSwipeToDismiss(true);
                        progressDialog.setClickClose(true);
                        progressDialog.show();
                    }
                });
    }

    /**
     * 隐藏加载进度
     */
    public void dismissProgressDialog() {
        runUiThread(
                new Runnable() {
                    @Override
                    public void run() {
                        // 把判断写在runOnUiThread外面导致有时dismiss无效，可能不同线程判断progressDialog.isShowing()结果不一致
                        if (progressDialog == null || progressDialog.isShowing() == false) {
                            Log.warn(
                                    TAG,
                                    "dismissProgressDialog  progressDialog == null"
                                            + " || progressDialog.isShowing() == false >> return;");
                            return;
                        }
                        progressDialog.hide();
                        progressDialog.destroy();
                    }
                });
    }
    // 显示与关闭进度弹窗方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    // 启动新Activity方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**
     * 打开新的Activity，向左滑入效果
     *
     * @param intent intent
     */
    public void toActivity(Intent intent) {
        toActivity(intent, true);
    }

    /**
     * 打开新的Activity
     *
     * @param intent intent
     * @param showAnimation showAnimation
     */
    public void toActivity(Intent intent, boolean showAnimation) {
        toActivity(intent, -1, showAnimation);
    }

    /**
     * 打开新的Activity，向左滑入效果
     *
     * @param intent intent
     * @param requestCode requestCode
     */
    public void toActivity(Intent intent, int requestCode) {
        toActivity(intent, requestCode, true);
    }

    /**
     * 打开新的Activity
     *
     * @param intent intent
     * @param requestCode requestCode
     * @param showAnimation showAnimation
     */
    public void toActivity(final Intent intent, final int requestCode, final boolean showAnimation) {
        runUiThread(
                new Runnable() {
                    @Override
                    public void run() {
                        if (intent == null) {
                            Log.warn(TAG, "toActivity  intent == null >> return;");
                            return;
                        }
                        // fragment中使用context.startActivity会导致在fragment中不能正常接收onActivityResult
                        if (requestCode < 0) {
                            startAbility(intent);
                        } else {
                            startAbilityForResult(intent, requestCode);
                        }
                    }
                });
    }

    public static void toActivity(Ability context, Intent intent, int RequestCode) {
        context.startAbilityForResult(intent, RequestCode);
    }

    public static void toActivity(Context context, Intent intent, int RequestCode) {
        context.startAbility(intent, RequestCode);
    }
    // 启动新Activity方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    // show short toast 方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**
     * 快捷显示short toast方法，需要long toast就用 Toast.makeText(string, Toast.LENGTH_LONG).show(); ---不常用所以这个类里不写
     *
     * @param stringResId stringResId
     */
    public void showShortToast(int stringResId) {
        try {
            showShortToast(ResTUtil.getString(context, stringResId));
        } catch (Exception e) {
            Log.error(
                    TAG,
                    "showShortToast  context.getResources().getString(resId)"
                            + " >>  catch (Exception e) {"
                            + e.getMessage());
        }
    }

    /**
     * 快捷显示short toast方法，需要long toast就用 Toast.makeText(string, Toast.LENGTH_LONG).show(); ---不常用所以这个类里不写
     *
     * @param string string
     */
    public void showShortToast(String string) {
        showShortToast(string, false);
    }

    /**
     * 快捷显示short toast方法，需要long toast就用 Toast.makeText(string, Toast.LENGTH_LONG).show(); ---不常用所以这个类里不写
     *
     * @param string string
     * @param isForceDismissProgressDialog isForceDismissProgressDialog
     */
    public void showShortToast(final String string, final boolean isForceDismissProgressDialog) {
        runUiThread(
                new Runnable() {
                    @Override
                    public void run() {
                        if (isForceDismissProgressDialog) {
                            dismissProgressDialog();
                        }
                        CommonUtil.showShortToast(context, string);
                    }
                });
    }
    // show short toast 方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    // 运行线程 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**
     * 在UI线程中运行，建议用这个方法代替runOnUiThread
     *
     * @param action action
     */
    public final void runUiThread(Runnable action) {
        if (isAlive() == false) {
            Log.warn(TAG, "runUiThread  isAlive() == false >> return;");
            return;
        }
        EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
        handler.postTask(action);
    }

    /**
     * 线程名列表
     */
    protected List<String> threadNameList;

    /**
     * 运行线程
     *
     * @param name name
     * @param runnable runnable
     * @return EventHandler
     */
    public final EventHandler runThread(String name, Runnable runnable) {
        if (isAlive() == false) {
            Log.warn(TAG, "runThread  isAlive() == false >> return null;");
            return null;
        }
        name = StringUtil.getTrimedString(name);
        EventHandler handler = ThreadManager.getInstance().runThread(name, runnable);
        if (handler == null) {
            Log.error(TAG, "runThread handler == null >> return null;");
            return null;
        }

        if (threadNameList.contains(name) == false) {
            threadNameList.add(name);
        }
        return handler;
    }

    // 运行线程 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

    // Activity的返回按钮和底部弹窗的取消按钮几乎是必备，正好原生支持反射；而其它比如Fragment极少用到，也不支持反射<<<<<<<<<

    /**
     * 返回按钮被点击，默认处理是onBottomDragListener.onDragBottom(false)，重写可自定义事件处理
     *
     * @param v v
     * @use layout.xml中的组件添加android:onClick="onReturnClick"即可
     * @warn 只能在Activity对应的contentView layout中使用；
     * *给对应View setOnClickListener会导致android:onClick="onReturnClick"失效
     */
    @Override
    public void onReturnClick(Component v) {
        Log.debug(TAG, "onReturnClick >>>");
        if (onBottomDragListener != null) {
            onBottomDragListener.onDragBottom(false);
        } else {
            onBackPressed(); // 会从最外层子类调finish();BaseBottomWindow就是示例
        }
    }

    /**
     * 前进按钮被点击，默认处理是onBottomDragListener.onDragBottom(true)，重写可自定义事件处理
     *
     * @param v v
     * @use layout.xml中的组件添加android:onClick="onForwardClick"即可
     * @warn 只能在Activity对应的contentView layout中使用；
     * *给对应View setOnClickListener会导致android:onClick="onForwardClick"失效
     */
    @Override
    public void onForwardClick(Component v) {
        Log.debug(TAG, "onForwardClick >>>");
        if (onBottomDragListener != null) {
            onBottomDragListener.onDragBottom(true);
        }
    }
    // Activity常用导航栏右边按钮，而且底部弹窗BottomWindow的确定按钮是必备；而其它比如Fragment极少用到，也不支持反射>>>>>

    @Override
    public final boolean isAlive() {
        return isAlive && context != null; // & ! isFinishing();导致finish，onDestroy内runUiThread不可用
    }

    @Override
    public final boolean isRunning() {
        return isRunning & isAlive();
    }

    /**
     *
     * 一般用于对不支持的数据的处理，比如onCreate中获取到不能接受的id(id<=0)可以这样处理
     * @param error error
     */
    public void finishWithError(String error) {
        showShortToast(error);
    }

    @Override
    protected void onForeground(Intent intent) {
        super.onForeground(intent);
        isRunning = true;
    }

    @Override
    protected void onBackground() {
        super.onBackground();
        isRunning = false;
    }

    /**
     * 销毁并回收内存
     *
     * @warn 子类如果要使用这个方法内用到的变量，应重写onDestroy方法并在super.onDestroy();前操作
     */
    @Override
    protected void onStop() {
        Log.debug(TAG, "\n onDestroy <<<<<<<<<<<<<<<<<<<<<<<");
        dismissProgressDialog();
        ThreadManager.getInstance().destroyThread(threadNameList);

        isAlive = false;
        isRunning = false;
        super.onStop();
        view = null;
        tvBaseTitle = null;

        progressDialog = null;
        threadNameList = null;

        intent = null;

        context = null;
    }

    // 手机返回键和菜单键实现同点击标题栏左右按钮效果<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

    /**
     * 是否长按
     * @return bo
     */
    public boolean isOnKeyLongPress() {
        return isOnKeyLongPress;
    }

    @Override
    public boolean onKeyPressAndHold(int keyCode, KeyEvent keyEvent) {
        isOnKeyLongPress = true;
        return super.onKeyPressAndHold(keyCode, keyEvent);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
        return super.onKeyDown(keyCode, keyEvent);
    }

    private boolean isOnKeyLongPress = false;

    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (isOnKeyLongPress) {
            isOnKeyLongPress = false;
            return true;
        }

        switch (keyCode) {
            case KeyEvent.KEY_BACK:
                if (onBottomDragListener != null) {
                    onBottomDragListener.onDragBottom(false);
                    return true;
                }
                break;
            case KeyEvent.KEY_MENU:
                if (onBottomDragListener != null) {
                    onBottomDragListener.onDragBottom(true);
                    return true;
                }
                break;
            default:
                break;
        }

        return super.onKeyUp(keyCode, event);
    }
}
